﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Windows.Forms;
using System.Drawing;
using simulatMeter;


namespace simulatMeter
{

    public enum MeterType{

        Meter07,
        Meter97,
        MeterNULL,

    };

    public enum DataType
    {
        bin,
        hex,
        all,
    }

    public enum DIITEMTYPE 
    {
        SN_TYPE,
        DI_TYPE,
        NAME_TYPE,
        LEN_TYPE,
        DATA_TYPE,
        TYPE_TYPE,
    };

    //数据项
    public class Didata
    {
        /// <summary>
        /// 序号
        /// </summary>
        public UInt32 SN;
        /// <summary>
        /// di码
        /// </summary>
        public UInt32 DI;
        /// <summary>
        /// 名称  
        /// </summary>
        public String Name;

        /// <summary>
        ///  数据长度
        /// </summary>
        public UInt16 Len;

        /// <summary>
        /// 数据内容，如果数据内容多项，以,分开
        /// </summary>
        public String Data;

        public DataType type;


        /// <summary>
        /// Constructor
        /// </summary>
        public Didata()
        {

            DI = 0x00000000;
            Name = "组合有功总电能 xxxxxx.xx Kwh";
            Len = 4;
            Data = "000000.00";
            type = DataType.all;

        }


        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="di"></param>
        /// <param name="name"></param>
        /// <param name="len"></param>
        /// <param name="data"></param>
        public Didata(UInt32 sn,UInt32 di, String name, UInt16 len, String data,DataType t)
        {
            DI = di; Name = name; Len = len; Data = data; SN = sn; type = t;
        }


        //字符串属性
        public String DI32String
        {
            get { return Ulitily.ShareClass.Hex32ToString(DI); }
            set {
                UInt32 dd = 0;
                String str = Ulitily.ShareClass.StringToHex32(value, ref dd);
                if (str != null) { DI = dd; }
                else
                {
                    throw (new Exception("DI不正确"));
                }
            }
        }
        public String DI16String
        {
            get { return Ulitily.ShareClass.Hex16ToString((UInt16)DI); }
            set
            {
                UInt16 dd = 0;
                String str = Ulitily.ShareClass.StringToHex16(value, ref dd);
                if (str != null) { DI = dd; }
                else
                {
                    throw (new Exception("DI不正确"));
                }
            }
        }
        public String LenString
        {
            get { return Len.ToString("D"); }
            set
            {
                try { 
                        UInt16 ll = UInt16.Parse(value, System.Globalization.NumberStyles.Number);
                        Len = ll;
                    }
                catch
                {
                    throw (new Exception("长度不正确"));
                }
            }
        }
        public String DataString 
        {
            get { return Data; }
            set
            {
                try
                {
                    if (type == DataType.all) { Data = value; }

                    switch (this.type)
                    {
                        case DataType.bin:
                            double d = double.Parse(value);
                            Data = value;
                            break;
                        case DataType.hex:
                            {
                                byte[] dddd = Ulitily.ShareClass.strToHexByteArray(value);
                                if (dddd != null)
                                {
                                    Data = value;
                                }
                                else throw (new Exception("数值无效"));
                            }
                            break;
                    }
                }
                catch
                {

                    throw (new Exception("数值不正确"));
                }

            }
        }
        public String DataTypeString
        {
            get{return type.ToString();}
            set
            {
                if (value.Replace(" ", "") == "bin") type = DataType.bin;
                else if (value.Replace(" ", "") == "hex") type = DataType.hex;
            }
        }

        public byte[] DataToBytes
        {
            get
            {
                if (Len == 0) return null;
                byte[] d = new byte[Len];
                byte[] dd = Ulitily.ShareClass.strToBinByteArray(DataString);


                int ll = dd.Length > d.Length ? d.Length : dd.Length;
                Array.Clear(d, 0, d.Length);
                Ulitily.ShareClass.ReversedBytes(dd, dd.Length);
                Array.Copy(dd, 0, d,0, ll);
                return d;
            }
        }
        /// <summary>
        /// 设置数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="indata"></param>
        /// <returns>返回设置后的数据，如果出错有messagebox</returns>
        public String ChangeValue(DIITEMTYPE type, String indata,MeterType mtype)
        {
   
            switch (type)
            {
                case DIITEMTYPE.DI_TYPE:
                    if (mtype == MeterType.Meter07) { DI32String = indata; return DI32String; }
                    else if (mtype == MeterType.Meter97) { DI16String = indata; return DI16String; }

                    break;

                case DIITEMTYPE.DATA_TYPE:
                    DataString = indata;
                    return DataString;

                case DIITEMTYPE.NAME_TYPE:
                    Name = indata;
                    return Name;
                case DIITEMTYPE.LEN_TYPE:
                    LenString = indata;
                    return LenString;
                case DIITEMTYPE.TYPE_TYPE:
                    DataTypeString = indata;
                    return DataTypeString;
                default: 
                    return null;
            }

            return null;
        }
    }


    /// <summary>
    /// 一个电表数据项数据
    /// </summary>
    public class MeterDiData
    {
        public UInt64 meterNumber;
        public Didata diData;
        public ConfigItem father;
        public byte[] di;
    }
    //电表数据配置文件
    public class ConfigItem
    {
        /// <summary>
        /// 是否使用
        /// </summary>
        public bool Usage;
        /// <summary>
        /// 配置名称
        /// </summary>
        public String configName;
        /// <summary>
        /// 电表表号
        /// </summary>
        public List<String> mlist;


        /// <summary>
        /// 电表类型
        /// </summary>
        public MeterType meterType;


        /// <summary>
        /// 电表所在的数据
        /// </summary>
        public List<Didata> dis;


        /// <summary>
        /// 构造
        /// </summary>
        public ConfigItem()
        {

            mlist = new List<String>();
            meterType = MeterType.MeterNULL;
            dis = new List<Didata>();
            Usage = false;
        }


        /// <summary>
        /// 修改一个di的数据
        /// </summary>
        /// <param name="index"></param>
        /// <param name="type"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public Didata ChangeDIValue(int index, DIITEMTYPE type,String data)
        {
            if (dis == null || dis.Count <= index) return null;
            switch (type)
            {
                case DIITEMTYPE.DATA_TYPE:
                    dis[index].DataString = data;
                    break;
                case DIITEMTYPE.DI_TYPE:
                    if (meterType == MeterType.Meter07) dis[index].DI32String = data;
                    if (meterType == MeterType.Meter97) dis[index].DI16String = data;
                    break;
                case DIITEMTYPE.LEN_TYPE:
                    dis[index].LenString = data;
                    break;
                case DIITEMTYPE.NAME_TYPE:
                    dis[index].Name = data;
                    break;
                case DIITEMTYPE.TYPE_TYPE:
                    dis[index].DataTypeString = data;
                    break;

                default: return null;
            }

            return dis[index];

        }

        /// <summary>
        /// 修改一个di的数据
        /// </summary>
        /// <param name="Values"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public Didata ChangeDIValue(String[] Values,int index)
        {
            ConfigItem currentitem = this;
            currentitem.ChangeDIValue(index, DIITEMTYPE.DI_TYPE, Values[0]);
            currentitem.ChangeDIValue(index, DIITEMTYPE.LEN_TYPE, Values[1]);
            currentitem.ChangeDIValue(index, DIITEMTYPE.TYPE_TYPE, Values[2]);
            currentitem.ChangeDIValue(index, DIITEMTYPE.DATA_TYPE, Values[3]);
            currentitem.ChangeDIValue(index, DIITEMTYPE.NAME_TYPE, Values[4]);

            return currentitem.dis[index];
        }


        /// <summary>
        /// 查找一个电表的一个数据项
        /// </summary>
        /// <param name="SNO"></param>
        /// <param name="DI"></param>
        /// <param name="OSNO">输出，实际电表号，0xffffffffffffffff时，表示没有电表号</param>
        /// <returns></returns>
        public MeterDiData GetMeterDiData(UInt32 DI)
        {
            MeterDiData data = new MeterDiData();
            data.father = this;
            {
                if (meterType == MeterType.Meter07)
                {
                    DI &= 0xffffffff;
                    data.di = new byte[4];
                    data.di[0] = (byte)(DI >> 0);
                    data.di[1] = (byte)(DI >> 8);
                    data.di[2] = (byte)(DI >> 16);
                    data.di[3] = (byte)(DI >> 24);

                }
                else if (meterType == MeterType.Meter97)
                {

                    DI &= 0xffff;
                    data.di = new byte[2];
                    data.di[0] = (byte)(DI >> 0);
                    data.di[1] = (byte)(DI >> 8);
                }
                else return null;

                //查找 di 码 
                foreach (Didata di in dis)
                {
                    if (DI == di.DI)
                    {
                        data.diData = di;
                        return data;
                    }
                }

            }
            return null;
        }



        /// <summary>
        /// 查找电表
        /// </summary>
        /// <param name="sno">，电表表号</param>
        /// <returns>返回通配的电表表号列表</returns>
        public List<UInt64> GetMeters(UInt64 sno)
        {
            //////////////////////////////////////////////////////////////////////////
            //没有电表
            if (mlist.Count <= 0) return null;

            //////////////////////////////////////////////////////////////////////////
            List<UInt64> mtNumber = new List<UInt64>();
            //全AA AA AA AA AA AA
            if (sno == 0xAAAAAAAAAAAA)   //------------------>对于全aa 是 搜表用的
            {
                foreach (String m in mlist)
                {
                    UInt64 mn = UInt64.Parse(m, System.Globalization.NumberStyles.HexNumber);
                    mtNumber.Add(mn);
                }

                return mtNumber;
            }

            //其它xxxxAAxxxxxx 支持通配符查找
            {
                UInt64 AA = 0;// xxxxAAxxxxxx
                UInt64 FF = 0;// xxxxFFxxxxxx
                //get AA FF
                {
                    for (int af = 0; af < 12; af++)
                    {
                        UInt64 A = 0x000000000000000A; A <<= (4 * af);
                        UInt64 F = 0x000000000000000F; F <<= (4 * af);
                        if ((sno & F) == A)
                        {
                            AA |= A; FF |= F;
                        }
                    }
                    //取反 FFFF00FFFFFF;
                    FF = ~FF;
                    // sno & FF 作为地址 查询地址列表 
                }

                //////////////////////////////////////////////////////////////////////////
                //查找通配
                int i = 0;
                for (i = 0; i < mlist.Count; i++)
                {
                    UInt64 m = UInt64.Parse(mlist[i], System.Globalization.NumberStyles.HexNumber);
                    if((sno & FF) == (m & FF))
                        mtNumber.Add(m);
                }
            }

            if (mtNumber.Count > 0) return mtNumber;
            else return null;
        }
        

    }

    //操作
    public class Config
    {


        /// <summary>
        /// 数据文件
        /// </summary>
        String filename = "config.ini";
        String fileData = null;
        List<String> _line = new List<String>();
        String line
        {
            get { 
                if(_line.Count>0)
                    return _line[_line.Count-1];
                else return null;
            }
            set { fileData += value+"\r\n"; _line.Add(value); }
        }

        /// <summary>
        /// 电表数据
        /// </summary>
        public List<ConfigItem> clist = new List<ConfigItem>();


        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public int SaveConfig(List<String> d)
        {
            StreamWriter rd;
            int count = 0;
            String fn = System.IO.Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + filename;
            try
            {

                rd = new StreamWriter(fn, false,Encoding.Default);
            }
            catch (Exception e)
            {
                System.Console.WriteLine("SaveConfig无法打开:" + fn);
                MessageBox.Show("SaveConfig无法打开文件" + fn);
                return -1;
            }


            //写入文件
            int i = 0;
            for (i = 0; i < d.Count; i++)
            {
                rd.WriteLine(d[i]);
            }


            rd.Close();



            return count;
        }


        /// <summary>
        /// 读取电表配置，返回配置个数
        /// </summary>
        /// <returns></returns>
        public int ReadConfig()
        {

            StreamReader rd;
            String fn = System.IO.Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + filename;
            try
            {

                rd = new StreamReader(fn, Encoding.Default);
            }
            catch (Exception e)
            {
                System.Console.WriteLine("logSettingRecover无法打开:" + fn);
                MessageBox.Show("logSettingRecover无法打开文件" + fn);
                return -1;
            }

            /*
                配置形式
             * <config>
             * config=07电表 //配置名称
             * Meters=1,2,3  //电表表号列表 
             * Type=Meter_7 //电表类型
             * DI1=[00000000][组合有功总电能xxxxxx.xxKwh][4][123.56] //数据
             * </config>
             */
            //String line = "";
            for (line = rd.ReadLine(); line != null; line = rd.ReadLine())
            {
                //配置开始
                if (line == "<config>")
                {
                    ConfigItem item = new ConfigItem();
                    for (line = rd.ReadLine(); line != null; line = rd.ReadLine())
                    {
                        Match m ;

                        //结束
                        if (line == "</config>") { break; };
                        //config name  config=07电表
                        if((m = Regex.Match(line, @"(config=[\w\W]*)")).Groups.Count>1)
                            item.configName = m.ToString().Substring(7);
                        //Meters   Meters=17,2,3,4,5,6,7,8
                        if ((m = Regex.Match(line, @"(Meters=[\w\W]*)")).Groups.Count > 1)
                        {
                            ///取得表号 
                            MatchCollection mm = Regex.Matches(line, @"(\d)+");
                            try
                            {
                                for (int i = 0; i < mm.Count; i++)
                                {
                                    item.mlist.Add(mm[i].Value);
                                }

                            }catch { }
                        }

                        //DI data    \[([\u4e00-\u9fa5]|\w)+[^\[]*
                        if ((m = Regex.Match(line, @"(DI\d+=)")).Groups.Count > 1)
                        {
                            Didata didata = new Didata();
                            MatchCollection tmp = Regex.Matches(m.Groups[1].Value, @"(\d+)");
                            didata.SN = UInt32.Parse(tmp[0].Value, System.Globalization.NumberStyles.Number);
                            //tmp = Regex.Matches(line, @"\[([\u4e00-\u9fa5]|\w)+[^\[]*");

                            //支持 assii 码s
                            tmp = Regex.Matches(line, @"\[([\u4E00-\u9FA5]|[\uFE30-\uFFA0]|\w|[\x00-\x5A]|[\x5C]|[\x5E-\x7F]])+[^\[]*");
                            if (tmp.Count >= 5)
                            {
                                String[] s = new String[] { tmp[0].Value, tmp[1].Value, tmp[2].Value, tmp[3].Value ,tmp[4].Value};
                                s[0] = s[0].Replace("[", "").Replace("]", "");
                                s[1] = s[1].Replace("[", "").Replace("]", "");
                                s[2] = s[2].Replace("[", "").Replace("]", "");
                                s[3] = s[3].Replace("[", "").Replace("]", "");
                                s[4] = s[4].Replace("[", "").Replace("]", "");

                                didata.DI = UInt32.Parse(s[0], System.Globalization.NumberStyles.HexNumber);
                                didata.Name = s[1];
                                didata.Len = UInt16.Parse(s[2], System.Globalization.NumberStyles.Number);
                                didata.Data = s[3];
                                didata.type = (DataType)Enum.Parse(typeof(DataType),s[4]);
                                item.dis.Add(didata);
                            }
                        }
                        //Type= Meter07
                        if ((m = Regex.Match(line, @"(Type=\s*)")).Groups.Count > 1)
                        {
                            if ((m = Regex.Match(line, @"(Meter\w*)")).Groups.Count > 1)
                            item.meterType = (MeterType)Enum.Parse(typeof(MeterType), m.Groups[1].Value);
                        }

                        //usage
                        if ((m = Regex.Match(line, @"usage=\s*")).Success)
                        {
                            if (Regex.Match(line, @"true").Success) item.Usage = true;
                            else if (Regex.Match(line, @"false").Success) item.Usage = false;
                        }

                    }

                    if (item.meterType != MeterType.MeterNULL)
                    {
                        this.clist.Add(item);
                    }
                }
            }
            rd.Close();
            return this.clist.Count;

        }

        public class MatchString
        {
            public string patten;
            public Match m;
            public int index;

            public MatchString() { patten = null; m = null; index = -1; }
            public MatchString(string p, Match mm, int i) { patten = p; m =mm; index = i; }
        }

        private MatchString GetLine(List<String> s, string patten, int startline,int endline)
        {
            MatchString ms = new MatchString(patten,null,-1);
            
            if (endline > s.Count) endline = s.Count;
            if(s==null ||s.Count<+startline)return ms;
            int i = 0;
            Match m;
            for (i = startline; i < s.Count; i++)
            {
                if (s[i] == null) continue;
                m = Regex.Match(s[i], patten);
                if (m != null && m.Success)
                {
                    ms.m = m;
                    ms.index = i;
                    return ms;
                }

            }

            return ms;
        }


        public enum optype {
        
            Add,
            Delete,
            Modify,
        }


        class ConfigInfo
        {
            public ConfigItem item;
            public MatchString startline;
            public MatchString endline;
        }

        /// <summary>
        /// 取得配置的信息
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        ConfigInfo GetConfigInfo(ConfigItem item)
        {
            ConfigInfo info = new ConfigInfo();
            {
                MatchString startline = new MatchString(null, null, 0), endline = new MatchString(null, null, 0);
                while (_line.Count > 0 && (startline = GetLine(_line, @"<config>", endline.index, _line.Count)).index >= 0)
                {
                    if ((endline = GetLine(_line, @"</config>", startline.index, _line.Count)).index <= startline.index) return null;


                    //在<config> </config>找configname
                    MatchString _nameline = GetLine(_line, @"(config=([\u4e00-\u9fa5]|\w)+)", startline.index, endline.index);
                    if (!(_nameline.m.Groups[1].Value == "config=" + item.configName))
                    {
                        continue;
                    }

                    //找到
                    info.startline = startline;
                    info.endline = endline;
                    info.item = item;
                    return info;
                }
            }

            return null;
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="item"></param>
        /// <param name="olddi">原di</param>
        /// <param name="newdi">新di</param>
        /// <param name="operator">1,修改  2.添加    3删除</param>
        /// <returns>-1:error  >=0 :line of di</returns>
        public int SaveDiData(ConfigItem item,Didata olddi, Didata newdi, optype op)
        {

            ConfigInfo info = GetConfigInfo(item);
            if (info != null)
            {
                MatchString startline = info.startline;
                MatchString endline = info.endline;

                //在startline ---endline之间找对应的di 
                string patten = null;
                if(item.meterType == MeterType.Meter07)patten =@"=\["+olddi.DI32String+@"\]";
                else if(item.meterType == MeterType.Meter97)patten = @"=\["+olddi.DI16String+@"\]";
                MatchString m = GetLine(_line,patten,startline.index,endline.index);

                //不存在
                if (m.m == null || m.m.Success == false || !(m.index > startline.index && m.index < endline.index))
                {
                    if (op == optype.Modify|| op == optype.Delete) return -1;

                    //添加
                    {
                        String mlinestring;
                        //对数据替换
                        mlinestring = "DI" + (newdi.SN).ToString("D") + "="
                            + "[" + ((item.meterType== MeterType.Meter07)?newdi.DI32String:newdi.DI16String) + "]"
                            + "[" + newdi.Name + "]"
                            + "[" + newdi.Len.ToString("D") + "]"
                            + "[" + newdi.DataString + "]"
                            + "[" + newdi.DataTypeString + "]";

                        _line.Insert(endline.index, mlinestring);

                        //save to file 
                        SaveConfig(_line);

                        //
                        return endline.index;

                    }

                }
                //////////////////////////////////////////////////////////////////////////
                //知道数据在哪一项了
                if(op == optype.Modify) //修改
                {
                    String mlinestring = _line[m.index];
                    //对数据替换
                    mlinestring = "DI"+ (newdi.SN).ToString("D")+"="
                        + "[" + ((item.meterType== MeterType.Meter07)?newdi.DI32String:newdi.DI16String) + "]"
                        + "[" + newdi.Name + "]"
                        + "[" + newdi.Len.ToString("D") + "]"
                        + "[" + newdi.DataString + "]"
                        + "[" + newdi.DataTypeString + "]";
                    _line[m.index] = mlinestring;

                    //save to file 
                    SaveConfig(_line);

                    //
                    return m.index;

                }

                if (op == optype.Delete) //删除
                {
                    _line.RemoveAt(m.index);
                    SaveConfig(_line);
                    return m.index;
                }
            }

            return -1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public int SaveUsage(ConfigItem item, bool Value)
        {
            ConfigInfo info = GetConfigInfo(item);
            if (info != null)
            {
                //找到usage行
                MatchString usage = GetLine(_line, @"usage=.+", info.startline.index, info.endline.index);
                if (usage.m.Success)
                {
                    if (Regex.Match(usage.m.Groups[1].Value, "true").Success && Value == true) return usage.index;
                    else if(Regex.Match(usage.m.Groups[1].Value, "false").Success && Value == false) return usage.index;

                    //修改
                    String newstring = "usage=" + Value.ToString();
                    _line[usage.index] = newstring.ToLower();
                    SaveConfig(_line);
                    item.Usage = Value;
                    return usage.index;
                }
            }return -1;
        }


        public int SaveMeters(ConfigItem item, List<String> meterList)
        {
            ConfigInfo info = GetConfigInfo(item);
            if (info != null)
            {
                //找到Meters行  Meters=1,2,3,4,5
                MatchString Meters = GetLine(_line, @"Meters=?", info.startline.index, info.endline.index);
                if (Meters.m.Success)
                {
                    
                    //修改
                    String newstring = "Meters=";
                    foreach (String s in meterList) newstring += s+",";
                    _line[Meters.index] = newstring;
                    SaveConfig(_line);
                    item.mlist = meterList;
                    return Meters.index;
                }
            } return -1;
        }
    }
}
